#include "server.hpp"

#include "../lge2d.hpp"

#include "lan_cfg.hpp"

namespace lge2d
{

namespace lan
{

namespace server
{

Server::Server() :
		m_port(DEFAULT_SERVER_PORT),
		m_state(ServerIsStopped)
{

}

Server::~Server()
{
	if (m_state != ServerIsStopped)
	{
		Terminate();
	}
}

void Server::SetPort(unsigned short port)
{
	m_port = port;
}

unsigned short Server::GetPort() const
{
	return m_port;
}

void Server::Start()
{
	if (m_state != ServerIsStopped)
		return;

	Initialize();

	if (m_state != ServerIsStarted)
		return;
	//
	m_state = ServerIsWorking;
}

void Server::Stop()
{
	if (m_state != ServerIsWorking)
		return;

	m_state = ServerIsStopping;
}

void Server::Initialize()
{
	m_client_connections.reserve(MAX_SEVER_CLIENTS);
	m_state = ServerIsStarting;
	if (!m_socket_listener.Listen(m_port))
	{
		lge2d::log->Error("can't create server on port %d", m_port);
		m_state = ServerIsStopped;
		return;
	}

	m_socket_listener.SetBlocking(false);
	m_state = ServerIsStarted;
}

void Server::Terminate()
{
	// close server socket
	if (m_socket_listener.IsValid())
		m_socket_listener.Close();

	unsigned clientsCount = GetClientsCount();
	for (size_t i = 0; i < clientsCount; ++i)
	{
		m_client_connections[i]->Disconnect();
	}
	m_client_connections.clear();

	m_state = ServerIsStopped;
}

Server::ServerState Server::GetState() const
{
	return m_state;
}

unsigned Server::GetClientsCount() const
{
	return m_client_connections.size();
}

void Server::Update(float dt)
{
	if (m_state == ServerIsWorking)
	{
		unsigned clientsCount = GetClientsCount();
		if (clientsCount < MAX_SEVER_CLIENTS)
		{
			sf::IPAddress address;
			sf::SocketTCP client;

			sf::Socket::Status status = m_socket_listener.Accept(client, &address);

			switch(status)
			{
			/// The socket is not ready to send / receive data yet
			case sf::Socket::NotReady:
				break;

			/// The socket has sent / received the data
			case sf::Socket::Done:
			{
				m_client_connections.push_back(ConnectionPtr(new Connection(client)));
				++clientsCount;
				lge2d::log->Info("[SERVE] Client connected ip: %s", address.ToString().c_str());
				break;
			}

			/// The TCP socket has been disconnected
			case sf::Socket::Disconnected:
				lge2d::log->Error("[SERVER] listener status is Disconnected.");
				break;

			/// An unexpected error happened
			case sf::Socket::Error:
				lge2d::log->Error("[SERVER] listener status is Error.");
				break;
			}
		}

		for (size_t i = 0; i < clientsCount; ++i)
		{
			bool res = m_client_connections[i]->Update(dt);
			if (res == false)
			{
				lge2d::log->Warning("[SERVER] client connection is not valid.");
				m_client_connections.erase(m_client_connections.begin() + i);
				--i;
				--clientsCount;
			}
		}
	}
	else if (m_state == ServerIsStopping)
	{
		Terminate();
	}
}

} /* namespace server */
} /* namespace lan */
} /* namespace lge2d */
